/*
 * @Author: ygnnli 1585923072@qq.com
 * @Date: 2024-08-16 16:30:16
 * @LastEditors: ygnnli 1585923072@qq.com
 * @LastEditTime: 2024-08-27 21:53:50
 * @FilePath: /bitrpc/source/server/rpc_router.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */

#pragma once
#include "../common/net.hpp"
#include "../common/message.hpp"

namespace bitrpc
{
    namespace server
    {
        // Value的类型
        enum class VType
        {
            BOOL = 0,     // 布尔类型
            INTEGRAL = 1, // 整数类型
            NUMERIC = 2,  // 浮点类型
            STRING = 3,   // 字符串类型
            ARRAY = 4,    // 数组类型
            OBJECT = 5,   // 对象类型
        };

        // 服务请求描述
        class ServiceDescribe
        {
        public:
            using ptr = std::shared_ptr<ServiceDescribe>;
            using ServiceCallback = std::function<void(const Json::Value &, Json::Value &)>; // 服务回调函数
            using ParamsDescribe = std::pair<std::string, VType>;                            // 参数描述:字段名,字段类型

            ServiceDescribe(std::string &&mname, std::vector<ParamsDescribe> &&desc, VType vtype, ServiceCallback &&handler)
                : _method_name(std::move(mname)), _params_describe(std::move(desc)), _return_type(vtype), _callback(std::move(handler))
            {
            }
            // 获取服务请求的方法名
            const std::string &method() const { return _method_name; }
            // 针对收到的请求中的参数进行校验
            bool paramCheck(const Json::Value &params)
            {
                // 对params进行参数校验---判断所描述的参数字段是否存在，类型是否一致
                for (auto &desc : _params_describe)
                {
                    // 判断当前参数字段在_params_describe中是否存在
                    if (params.isMember(desc.first) == false)
                    {
                        ELOG("参数字段完整性校验失败! %s 字段缺失!", desc.first.c_str());
                        return false;
                    }
                    // 判断当前参数字段的类型是否一致
                    if (check(desc.second, params[desc.first]) == false)
                    {
                        ELOG("%s 参数字段类型校验失败! ", desc.first.c_str());
                        return false;
                    }
                }
                return true;
            }
            // 调用实际的服务回调函数
            bool call(const Json::Value &params, Json::Value &result)
            {
                _callback(params, result); // 调用回调函数
                if (rtypeCheck(result) == false)
                {
                    ELOG("回调处理函数中的响应信息校验失败!");
                    return false;
                }
                return true;
            }

        private:
            // 针对收到的请求中的结果进行校验
            bool rtypeCheck(const Json::Value &result)
            {
                return check(_return_type, result);
            }

            bool check(VType vtype, const Json::Value &val)
            {
                // 根据vtype判断val的类型是否一致
                switch (vtype)
                {
                case VType::BOOL:
                    return val.isBool();
                case VType::INTEGRAL:
                    return val.isIntegral();
                case VType::NUMERIC:
                    return val.isNumeric();
                case VType::STRING:
                    return val.isString();
                case VType::ARRAY:
                    return val.isArray();
                case VType::OBJECT:
                    return val.isObject();
                }
                return false;
            }

        private:
            std::string _method_name;                     // 方法名称
            ServiceCallback _callback;                    // 实际的业务回调函数
            std::vector<ParamsDescribe> _params_describe; // 参数字段格式的描述
            VType _return_type;                           // 结果作为返回值类型的描述
        };

        // 服务描述的构建工厂
        class SDescribeFactory
        {
        public:
            void setMethodName(const std::string &mname)
            {
                //ELOG("服务请求描述:设置方法名称");
                _method_name = mname;
            }
            void setReturnType(VType vtype)
            {
                //ELOG("服务请求描述:设置返回值类型");
                _return_type = vtype;
            }
            void setParamsDesc(const std::string &pname, VType vtype)
            {
                //ELOG("服务请求描述:设置参数字段描述");
                _params_describe.push_back(ServiceDescribe::ParamsDescribe(pname, vtype));
            }
            void setCallback(const ServiceDescribe::ServiceCallback &cb)
            {
                //ELOG("服务请求描述:设置回调函数");
                _callback = cb;
            }
            ServiceDescribe::ptr build()
            {
                //ELOG("构建服务描述对象");
                return std::make_shared<ServiceDescribe>(std::move(_method_name), std::move(_params_describe), _return_type, std::move(_callback));
            }

        private:
            std::string _method_name;                                      // 方法名称
            ServiceDescribe::ServiceCallback _callback;                    // 实际的业务回调函数
            std::vector<ServiceDescribe::ParamsDescribe> _params_describe; // 参数字段格式的描述
            VType _return_type;                                            // 结果作为返回值类型的描述
        };

        // 服务管理
        class ServiceManager
        {
        public:
            using ptr = std::shared_ptr<ServiceManager>;
            // 新增服务
            void insert(const ServiceDescribe::ptr &desc)
            {
                //ELOG("新增服务");
                std::unique_lock<std::mutex> lock(_mutex);
                _service.insert(std::make_pair(desc->method(), desc)); // 服务名称到服务描述的映射
            }
            // 查询服务
            ServiceDescribe::ptr select(const std::string &method_name)
            {
                //ELOG("查询服务");
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _service.find(method_name);
                if (it == _service.end())
                {
                    return ServiceDescribe::ptr(); // 空对象
                }
                return it->second;
            }
            // 删除服务
            void remove(const std::string &method_name)
            {
                //ELOG("删除服务");
                std::unique_lock<std::mutex> lock(_mutex);
                _service.erase(method_name); // 删除方法
            }

        private:
            std::mutex _mutex;                                              // 互斥锁
            std::unordered_map<std::string, ServiceDescribe::ptr> _service; // 服务名称到服务描述的映射
        };

        // rpc请求路由
        class RpcRouter
        {
        public:
            using ptr = std::shared_ptr<RpcRouter>;
            RpcRouter() : _service_manager(std::make_shared<ServiceManager>())
            {
            }
            // 这是注册到Dispatcher模块针对rpc请求进行回调处理的业务函数
            void onRpcRequest(const BaseConnection::ptr &conn, RpcRequest::ptr &request)
            {
                //ELOG("处理rpc请求");
                // 1.查询客户端请求的方法描述---判断当前服务端是否提供对应的服务
                auto service = _service_manager->select(request->method()); // 查询服务
                if (service.get() == nullptr)
                {
                    ELOG("%s 服务未找到!", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_NOT_FOUND_SERVICE); // 服务未找到
                }
                // 2.进行参数校验,确定能否提供服务
                if (service->paramCheck(request->params()) == false)
                {
                    ELOG("%s 服务参数校验失败!", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_INVALID_PARAMS); // 参数校验失败
                }
                // 3.调用业务回调接口进行业务处理
                Json::Value result;
                bool ret = service->call(request->params(), result); // 调用业务回调接口
                if (ret == false)
                {
                    ELOG("%s 服务调用失败!", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_INTERNAL_ERROR); // 服务调用失败
                }
                // 4.处理完毕得到的结果,组织响应,发送给客户端
                return response(conn, request, result, RCode::RCODE_OK); // 服务调用成功
            }

            // 注册服务
            void registerMethod(const ServiceDescribe::ptr &service)
            {
                //ELOG("注册服务");
                return _service_manager->insert(service);
            }

        private:
            void response(const BaseConnection::ptr &conn, const RpcRequest::ptr &req, const Json::Value &res, RCode rcode)
            {
                auto msg = MessageFactory::create<RpcResponse>();
                msg->setId(req->rid());
                msg->setMType(bitrpc::MType::RSP_RPC);
                msg->setRCode(rcode);
                msg->setResult(res);
                conn->send(msg);
            }

        private:
            ServiceManager::ptr _service_manager; // 服务管理器
        };
    }
}